﻿// Copyright (c) 2012 Mokah Nnamezie & Andrew Cooper
// Neo4Net graph database - http://neo4net.codeplex.com
//
// This file is part of Neo4Net - a .Net port of the Neo4j graph database
//
// Neo4Net is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

namespace Neo4Net.Kernel.Impl.Core
{
    using System.IO;
    using Neo4Net.GraphDb;
    using Neo4Net.GraphDb.Factory;
    using Neo4Net.Kernel.Impl.Util;
    using NUnit.Framework;

    [TestFixture]
    public class TestIdReuse
    {
        [Test]
        public void MakeSureIdsGetsReusedForPropertyStore()
        {
            MakeSureIdsGetsReused("neostore.propertystore.db", 10, 200);
        }

        [Test]
        public void MakeSureIdsGetsReusedForArrayStore()
        {
            long[] array = new long[500];
            for (int i = 0; i < array.Length; i++)
            {
                array[i] = 0xFFFFFFFFFFFFL + i;
            }
            MakeSureIdsGetsReused("neostore.propertystore.db.arrays", array, 20);
        }

        [Test]
        public void MakeSureIdsGetsReusedForStringStore()
        {
            string str = "something";
            for (int i = 0; i < 100; i++)
            {
                str += "something else " + i;
            }
            MakeSureIdsGetsReused("neostore.propertystore.db.strings", str, 20);
        }

        private void MakeSureIdsGetsReused(string fileName, object value, int iterations)
        {
            var storeDir = new DirectoryInfo("target/var/idreuse");
            FileUtils.DeleteRecursively(storeDir);
            FileInfo file = new FileInfo(Path.Combine(storeDir.FullName, fileName));
            IGraphDatabaseService db = new GraphDatabaseFactory().NewEmbeddedDatabaseBuilder(storeDir.FullName)
                                                                 .SetConfig(GraphDatabaseSettings.UseMemoryMappedBuffers.Name, GraphDatabaseSetting.BooleanSetting.False)
                                                                 .NewGraphDatabase();
            for (int i = 0; i < 5; i++)
            {
                SetSomeAndRemoveSome(db.ReferenceNode, value);
            }
            db.Shutdown();
            long sizeBefore = file.Length;
            db = new GraphDatabaseFactory().NewEmbeddedDatabase(storeDir.FullName);
            for (int i = 0; i < iterations; i++)
            {
                SetSomeAndRemoveSome(db.ReferenceNode, value);
            }
            db.Shutdown();
            Assert.That(file.Length, Is.EqualTo(sizeBefore));
        }

        private void SetSomeAndRemoveSome(INode node, object value)
        {
            ITransaction tx = node.GraphDatabase.BeginTx();
            try
            {
                for (int i = 0; i < 10; i++)
                {
                    node.SetProperty("key" + i, value);
                }
                tx.Success();
            }
            finally
            {
                tx.Finish();
            }
            tx = node.GraphDatabase.BeginTx();
            try
            {
                for (int i = 0; i < 10; i++)
                {
                    node.RemoveProperty("key" + i);
                }
                tx.Success();
            }
            finally
            {
                tx.Finish();
            }
        }
    }
}
